home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / vtrm / part01 next >
Encoding:
Internet Message Format  |  1987-02-11  |  28.3 KB

  1. Subject:  v08i059:  A Unix/PC virtual terminal package, Part01/02
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Guido van Rossum <seismo!mcvax!guido>
  6. Mod.sources: Volume 8, Issue 59
  7. Archive-name: vtrm/Part01
  8.  
  9. [  This package provides duplicate functionality for Unix and PC
  10.    screen-oriented programs.  (Is that sentence in English?)
  11.    A Makefile doesn't make sense, and I guess I'm being nice by
  12.    not sticking to my requirement for a manpage.  Comments on that,
  13.    anyone?  I have not done anything to or with these programs, other
  14.    than to re-shar them.  -r$  ]
  15.  
  16. As the README file mentions, there is little documentation and no
  17. test program.  Adding all the stuff to make it into a "neat" posting
  18. would cost me a day or two, which I simply can't spare.  I believe that
  19. it is useful enough in its current state.
  20.     Guido van Rossum, CWI, Amsterdam <guido@mcvax.uucp>
  21.  
  22. #! /bin/sh
  23. # This is a shell archive.  Remove anything before this line,
  24. # then unpack it by saving it in a file and typing "sh file".
  25. # If all goes well, you will see the message "End of archive 1 (of 2)."
  26. # Contents:  README p1trm.c trm.h MANIFEST
  27. PATH=/bin:/usr/bin:/usr/ucb; export PATH
  28. echo shar: extracting "'README'" '(2381 characters)'
  29. if test -f 'README' ; then 
  30.   echo shar: will not over-write existing file "'README'"
  31. else
  32. sed 's/^X//' >README <<'@//E*O*F README//'
  33. XTHIS IS VTRM
  34. X============
  35. X
  36. XVTRM is a terminal control package, with two implementations: one for Unix
  37. X(only well-tested on 4.2/4.3 BSD, but supposedly running under System 5
  38. Xas well, as long as there is a termcap database), and one for MS-DOS, to
  39. Xbe compiled with the Microsoft C compiler (tested only with version 3.0).
  40. XThis is a "curses replacement", which does not mean it is a curses
  41. Xreimplementation: the interface is totally different, only the purpose
  42. Xis more or less the same: to shield an application program from the
  43. Xnitty-gritty detail of cursor navigation, inverse video, scrolling, etc.
  44. XThere are also a few routines for CBREAK-mode input.
  45. X
  46. XUNPACKING NOTES
  47. X
  48. XThe shars yield five files:
  49. X    README        (this file)
  50. X    trm.h        (common header file)
  51. X    p1trm.c        (MS-DOS version)
  52. X    vtrm.c_1
  53. X    vtrm.c_2
  54. XThe latter two should be pasted together to get a file named vtrm.c:
  55. X    cat vtrm.c_[12] >vtrm.c
  56. X
  57. XAPOLOGY
  58. X
  59. XI must apologize for the poor documentation.  Most of it has the form of
  60. Xcomments in the source files (note the "specs" for the entire package at
  61. Xthe end of vtrm.c).  This is a library package but I do not have an
  62. Xadequate test program for it; I usually test it with one of the two
  63. Xapplications that use it -- these are too big to include in this posting.
  64. X
  65. XFUTURE DIRECTIONS
  66. X
  67. XThis version of VTRM is by no means an end point in its development.
  68. XWork is under way for an implementation that provides the same interface
  69. Xon the Macintosh.  You are invided to engage in implementations for othr
  70. Xmachines, such as as the Atari ST and the Commodore Amiga.  Comments on
  71. Xthe interface are more than welcome, and should be sent by electronic
  72. Xmail to guido@mcvax.uucp; this is also the address for bugfixes and
  73. Xother questions.
  74. X
  75. XAUTHORS
  76. X
  77. XThis software was written by:
  78. X
  79. X    Timo Krijnen and Guido van Rossum
  80. X    CWI, dept. AA
  81. X    Kruislaan 413
  82. X    1089 SJ  Amsterdam
  83. X    The Netherlands
  84. X
  85. X    Electronic mail: timo@mcvax.uucp,  guido@mcvax.uucp
  86. X    Phone: ... 20 - 592 4138.
  87. X
  88. XCOPYRIGHT
  89. X
  90. XThis software is copyright (c) 1986 by Stichting Mathematisch Centrum,
  91. XAmsterdam, The Netherlands.  Its use is allowed freely for
  92. Xnon-commercial purposes only.  Use at your own risk: SMC does not take
  93. Xresponsibility for the proper functioning of the software or for damage
  94. Xcaused by its use.  Redistribution is allowed for non-commercial
  95. Xpurposes only, and only unchanged, in its entirety, and including this
  96. Xcopyright notice.
  97. @//E*O*F README//
  98. if test 2381 -ne "`wc -c <'README'`"; then
  99.     echo shar: error transmitting "'README'" '(should have been 2381 characters)'
  100. fi
  101. fi # end of overwriting check
  102. echo shar: extracting "'p1trm.c'" '(21268 characters)'
  103. if test -f 'p1trm.c' ; then 
  104.   echo shar: will not over-write existing file "'p1trm.c'"
  105. else
  106. sed 's/^X//' >p1trm.c <<'@//E*O*F p1trm.c//'
  107. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  108. X
  109. X/*
  110. X * ibm Pc virtual TeRMinal package.
  111. X *
  112. X * An implementation of the VTRM interface for MS-DOS machines.
  113. X *
  114. X * This code supports two MODE's of accessing the screen.
  115. X * The first one (BIOS) will be used, unless the user overwrites this
  116. X * by setting the SCREEN environment variable.
  117. X * This variable can also be used to convey a screen size that differs
  118. X * from the default 25 lines and 80 columns. See below.
  119. X *
  120. X * The two modes are:
  121. X *
  122. X * 1) IBM BIOS interrupt 10 hex, video io.
  123. X *    (See IBM PC XT Technical Reference 6936833, May 1983,
  124. X *     Appendix A, pages A46-A47).
  125. X *    This is what you really want to use, since it's the only one that
  126. X *    can decently scroll. It cannot insert or delete characters, so
  127. X *    most optimisations from vtrm.c are useless and taken out.
  128. X *    Unfortunately, not every PC-compatible machine supports this BIOS
  129. X *    interrupt, so for these unlucky souls there is the following escape:
  130. X *
  131. X * 2) The ANSI.SYS driver.
  132. X *    (See IBM MS-DOS 6936839, Jan 1983, Version 2.00, Chapter 13.)
  133. X *    (Some compatibles don't have a separate ANSI.SYS driver but do the
  134. X *    same escape interpretation by default.)
  135. X *    This works reasonably, apart from scrolling downward, or part of
  136. X *    the screen, which is clumsy.
  137. X *    (The ANSI standard provides an escape sequence for scrolling
  138. X *    but ANSI.SYS does not support it, nor any other way of scrolling.)
  139. X *
  140. X * The rest of the interface is the same as described in vtrm.c,
  141. X * with the following exceptions:
  142. X *    - to ease coding for ansi scrolls, the terminal is supposed to
  143. X *    contain blanks at positions that were not written yet;
  144. X *    the unknown rubbish that is initially on the screen can
  145. X *    only be cleared by the caller by scrolling the whole screen up
  146. X *    by one or more lines;
  147. X *    - the number of lines on the terminal is assumed to be 25;
  148. X *    the number of columns is (1) determined by a BIOS function, or
  149. X *    (2) assumed to be 80 for ANSI;
  150. X *    the user can overwrite this by setting the environment variable:
  151. X *
  152. X *        SET SCREEN=BIOS x y
  153. X *    or
  154. X *        SET SCREEN=ANSI x y
  155. X *
  156. X *    where x and y are the number of lines and columns respectively.
  157. X *
  158. X * The lines and columns of our virtual terminal are numbered
  159. X *    y = {0...lines-1} from top to bottom, and
  160. X *    x = {0...cols-1} from left to right,
  161. X * respectively.
  162. X *
  163. X * The Visible Procedures in this package are as described in vtrm.c.
  164. X *
  165. X */
  166. X
  167. X/*
  168. X * Includes and data definitions.
  169. X */
  170. X
  171. X#include <stdio.h>
  172. X#include <signal.h>
  173. X#include <ctype.h>
  174. X#include <dos.h>
  175. X
  176. Xchar *malloc();
  177. X
  178. X#include "trm.h"
  179. X
  180. X#ifdef lint
  181. X#define VOID (void)
  182. X#else
  183. X#define VOID
  184. X#endif
  185. X
  186. X#define Forward
  187. X#define Visible
  188. X#define Hidden static
  189. X#define Procedure
  190. X
  191. Xtypedef short intlet;
  192. Xtypedef char *string;
  193. Xtypedef char bool;
  194. X#define Yes '\1'
  195. X#define No  '\0'
  196. X#define Undefined (-1)
  197. X
  198. X#define Min(a,b) ((a) <= (b) ? (a) : (b))
  199. X
  200. X#define MESS(number, text) text
  201. X
  202. X#ifdef GFX
  203. X#include "gfx.h"
  204. X#endif
  205. X
  206. X/* terminal status */
  207. X
  208. XHidden int started = No;
  209. X
  210. XHidden int scr_mode = 0;
  211. X#define ANSI 'A'
  212. X#define BIOS 'B'
  213. X
  214. X#define Nlines    25
  215. X#define Ncols    80
  216. XHidden int lines = Nlines;
  217. XHidden int cols = Ncols;
  218. XHidden int flags = 0;
  219. X
  220. X/* current standout mode */
  221. X#define Off    0
  222. X#define On    0200
  223. XHidden int so_mode = Off;
  224. X
  225. X/* masks for char's and intlet's */
  226. X#define NULCHAR '\000'
  227. X#define CHAR    0177
  228. X#define SOBIT    On
  229. X#define SOCHAR    0377
  230. X
  231. X/* current cursor position */
  232. XHidden intlet cur_y = Undefined, cur_x = Undefined;
  233. X
  234. X/* "line[y][x]" holds the char on the terminal, with the SOBIT.
  235. X * the SOBIT tells whether the character is standing out.
  236. X * "lenline[y]" holds the length of the line.
  237. X * (Partially) empty lines are distinghuished by "lenline[y] < cols".
  238. X * Unknown chars will be ' ', so the scrolling routines for ANSI
  239. X * can use "unwritten" chars (with indent > 0 in trmputdata).
  240. X * To make the optimising compare in putline fail, lenline[y] is initially 0.
  241. X * The latter implies that if a line is first addressed with trmputdata,
  242. X * any rubbish that is on the screen beyond the data that gets put, will
  243. X * remain there.
  244. X */
  245. XHidden char **line = 0;
  246. XHidden intlet *lenline = 0;
  247. X
  248. X/* Make the cursor invisible when trmsync() tries to move outside the screen */
  249. XHidden bool no_cursor = No;
  250. X
  251. X/*
  252. X * Starting, Ending and (fatal) Error.
  253. X */
  254. X
  255. X/*
  256. X * Initialization call.
  257. X * Determine terminal mode.
  258. X * Start up terminal and internal administration.
  259. X * Return Yes if succeeded, No if trouble (which doesn't apply here).
  260. X */
  261. XVisible int
  262. Xtrmstart(plines, pcols, pflags)
  263. Xint *plines;
  264. Xint *pcols;
  265. Xint *pflags;
  266. X{
  267. X    static char setup = No;
  268. X    int err;
  269. X
  270. X#ifdef TRACE
  271. Xif (!setup) freopen("TRACE.DAT", "a", stderr);
  272. Xfprintf(stderr, "\ttrmstart(&li, &co, &fl);\n");
  273. X#endif
  274. X
  275. X    if (started)
  276. X        return TE_TWICE;
  277. X
  278. X#ifdef GFX
  279. X    if (gfx_mode != TEXT_MODE)
  280. X        gfx_mode= SPLIT_MODE;
  281. X#endif
  282. X
  283. X    if (!setup) {
  284. X        err= set_screen_up();
  285. X        if (err != TE_OK)
  286. X            return err;
  287. X        setup = Yes;
  288. X    }
  289. X
  290. X    err= start_trm();        /* internal administration */
  291. X    if (err != TE_OK)
  292. X        return err;
  293. X
  294. X    *plines = lines;
  295. X    *pcols = cols;
  296. X    *pflags = flags;
  297. X
  298. X    set_handler();
  299. X    started = Yes;
  300. X    return TE_OK;
  301. X}
  302. X
  303. XHidden int
  304. Xset_screen_up()
  305. X{
  306. X    int height;
  307. X    int width;
  308. X    int get_screen_env();
  309. X    int get_cols();
  310. X
  311. X    height = width = 0;
  312. X    scr_mode = get_screen_env(&height, &width);
  313. X
  314. X    switch (scr_mode) {
  315. X    case BIOS:
  316. X    case TE_OK:
  317. X        cols = get_cols();
  318. X        flags = HAS_STANDOUT|CAN_SCROLL;
  319. X        break;
  320. X    case ANSI:
  321. X        flags = HAS_STANDOUT;
  322. X        break;
  323. X    default:
  324. X        return scr_mode; /* Error flag */
  325. X    }
  326. X
  327. X    /* allow x and y in environment variable SCREEN to override */
  328. X    if (height > 0)
  329. X        lines = height;
  330. X    if (width > 0)
  331. X        cols = width;
  332. X    return TE_OK;
  333. X}
  334. X
  335. XHidden int
  336. Xget_screen_env(pheight, pwidth)
  337. X    int *pheight, *pwidth;
  338. X{
  339. X    string s;
  340. X    int mode;
  341. X    char screrr;
  342. X    string getenv();
  343. X    string strip();
  344. X    string skip();
  345. X
  346. X    screrr = No;
  347. X    s = getenv("SCREEN");
  348. X    if (s == NULL)
  349. X        return BIOS;
  350. X
  351. X    s = strip(s);
  352. X    switch (*s) {
  353. X    case '\0':
  354. X        return BIOS;
  355. X    case 'a':
  356. X        mode = ANSI;
  357. X        s = skip(s, "ansi");
  358. X        break;
  359. X    case 'A':
  360. X        mode = ANSI;
  361. X        s = skip(s, "ANSI");
  362. X        break;
  363. X    case 'b':
  364. X        mode = BIOS;
  365. X        s = skip(s, "bios");
  366. X        break;
  367. X    case 'B':
  368. X        mode = BIOS;
  369. X        s = skip(s, "BIOS");
  370. X        break;
  371. X    default:
  372. X        mode = BIOS;
  373. X        screrr = Yes;
  374. X    }
  375. X
  376. X    /* *pheight and *pwidth were set to 0 above */
  377. X    s = strip(s);
  378. X    while (isdigit(*s)) {
  379. X        *pheight = *pheight * 10 + (*s++ - '0');
  380. X    }
  381. X    s = strip(s);
  382. X    while (isdigit(*s)) {
  383. X        *pwidth = *pwidth * 10 + (*s++ -'0');
  384. X    }
  385. X    s = strip(s);
  386. X    if (screrr || *s != '\0')
  387. X        return TE_BADTERM;
  388. X
  389. X    return mode;
  390. X}
  391. X
  392. XHidden string strip(s)
  393. Xstring s;
  394. X{
  395. X    while (*s == ' ' || *s == '\t')
  396. X        ++s;
  397. X    return s;
  398. X}
  399. X
  400. XHidden string skip(s, pat)
  401. Xstring s, pat;
  402. X{
  403. X    while (*s == *pat)
  404. X        ++s, ++pat;
  405. X    return s;
  406. X}
  407. X
  408. XHidden int        /* initialise internal administration */
  409. Xstart_trm()
  410. X{
  411. X    register int y;
  412. X
  413. X    if (line == 0) {
  414. X        if ((line = (char**) malloc(lines * sizeof(char*))) == NULL)
  415. X            return TE_NOMEM;
  416. X        for (y = 0; y < lines; y++) {
  417. X            if ((line[y] = malloc(cols * sizeof(char))) == NULL)
  418. X                return TE_NOMEM;
  419. X        }
  420. X    }
  421. X    if (lenline == 0) {
  422. X        if ((lenline = (intlet *)
  423. X                malloc(lines * sizeof(intlet))) == NULL)
  424. X            return TE_NOMEM;
  425. X    }
  426. X
  427. X    trmundefined();
  428. X    return TE_OK;
  429. X}
  430. X
  431. X/*
  432. X * Termination call.
  433. X * Beware that it might be called by a catched interrupt even in the middle
  434. X * of trmstart()!
  435. X */
  436. X
  437. XVisible Procedure
  438. Xtrmend()
  439. X{
  440. X#ifdef TRACE
  441. Xfprintf(stderr, "\ttrmend();\n");
  442. X#endif
  443. X    if (started && so_mode != Off)
  444. X        standend();
  445. X    if (scr_mode == ANSI) {
  446. X        VOID fflush(stdout);
  447. X    }
  448. X
  449. X    started = No;
  450. X}
  451. X
  452. X/*
  453. X * Set all internal statuses to undefined, especially the contents of
  454. X * the screen, so a hard redraw will not be optimised to heaven.
  455. X */
  456. X
  457. XVisible Procedure
  458. Xtrmundefined()
  459. X{
  460. X    register int y, x;
  461. X#ifdef TRACE
  462. Xfprintf(stderr, "\ttrmundefined();\n");
  463. X#endif
  464. X
  465. X    cur_y = cur_x = Undefined;
  466. X    so_mode = Undefined;
  467. X
  468. X    for (y = 0; y < lines; y++) {
  469. X        for (x = 0; x < cols; x++)
  470. X            line[y][x] = ' ';
  471. X            /* they may get printed in scrolling */
  472. X        lenline[y] = 0;
  473. X    }
  474. X}
  475. X
  476. X#ifdef DEBUG
  477. XHidden Procedure
  478. Xcheck_started(m)
  479. X    char *m;
  480. X{
  481. X    if (!started) {
  482. X        printf("Not started: %s\n", m);
  483. X        exit(TE_TWICE);
  484. X    }
  485. X}
  486. X#else
  487. X#define check_started(m) /*empty*/
  488. X#endif
  489. X
  490. X/*
  491. X * Sensing the cursor.
  492. X * (NOT IMPLEMENTED, since there is no way to locally move the cursor.)
  493. X */
  494. X
  495. X/*
  496. X * Sense the current (y, x) cursor position, after a possible manual
  497. X * change by the user with local cursor motions.
  498. X * If the terminal cannot be asked for the current cursor position,
  499. X * or if the string returned by the terminal is garbled,
  500. X * the position is made Undefined.
  501. X */
  502. XVisible Procedure
  503. Xtrmsense(py, px)
  504. X    int *py;
  505. X    int *px;
  506. X{
  507. X/*    bool getpos(); */
  508. X#ifdef TRACE
  509. Xfprintf(stderr, "\ttrmsense(&yy, &xx);\n");
  510. X#endif
  511. X    check_started(MESS(7904, "trmsense called outside trmstart/trmend"));
  512. X
  513. X    *py = *px = Undefined;
  514. X
  515. X/*
  516. X *    if (flags&CAN_SENSE && getpos(py, px)) {
  517. X *        if (*py < 0 || lines <= *py || *px < 0 || cols <= *px)
  518. X *            *py = *px = Undefined;
  519. X *    }
  520. X */
  521. X    cur_y = *py;
  522. X    cur_x = *px;
  523. X}
  524. X
  525. X/*
  526. X * Putting data on the screen.
  527. X */
  528. X
  529. X/*
  530. X * Fill screen area with given data.
  531. X * Characters with the SO-bit (0200) set are put in standout mode.
  532. X * (Unfortunately this makes it impossible to display accented characters.
  533. X * The interface should change.)
  534. X */
  535. XVisible Procedure
  536. Xtrmputdata(yfirst, ylast, indent, data)
  537. Xint yfirst;
  538. Xint ylast;
  539. Xregister int indent;
  540. Xregister string data;
  541. X{
  542. X    register int y;
  543. X    int x, len, lendata, space;
  544. X
  545. X#ifdef TRACE
  546. Xfprintf(stderr, "\ttrmputdata(%d, %d, %d, \"%s\");\n", yfirst, ylast, indent, data);
  547. X#endif
  548. X    check_started(MESS(7905, "trmputdata called outside trmstart/trmend"));
  549. X
  550. X    if (yfirst < 0)
  551. X        yfirst = 0;
  552. X    if (ylast >= lines)
  553. X        ylast = lines-1;
  554. X    space = cols*(ylast-yfirst+1) - indent;
  555. X    if (space <= 0)
  556. X        return;
  557. X    yfirst += indent/cols;
  558. X    indent %= cols;
  559. X    y = yfirst;
  560. X    if (data) {
  561. X        x = indent;
  562. X        lendata = strlen(data);
  563. X        if (ylast == lines-1 && lendata >= space)
  564. X            lendata = space - 1;
  565. X        len = Min(lendata, cols-x);
  566. X        while (y <= ylast) {
  567. X            put_line(y, x, data, len);
  568. X            y++;
  569. X            lendata -= len;
  570. X            if (lendata > 0) {
  571. X                x = 0;
  572. X                data += len;
  573. X                len = Min(lendata, cols);
  574. X            }
  575. X            else
  576. X                break;
  577. X        }
  578. X    }
  579. X    if (y <= ylast)
  580. X        clear_lines(y, ylast);
  581. X}
  582. X
  583. X/*
  584. X * We will try to get the picture:
  585. X *
  586. X *            op>>>>>>>>>>>op                       oq
  587. X *            ^         ^                       ^
  588. X *         <xskip><-----m1----><---------------od-------------------->
  589. X *   OLD:   "You're in a maze of twisty little pieces of code, all alike"
  590. X *   NEW:       "in a maze of little twisting pieces of code, all alike"
  591. X *            <-----m1----><----------------nd--------------------->
  592. X *            ^         ^                     ^
  593. X *            np>>>>>>>>>>>np                     nq
  594. X * where
  595. X *    op, oq, np, nq are pointers to start and end of Old and New data,
  596. X * and
  597. X *    xskip = length of indent to be skipped,
  598. X *    m1 = length of Matching part at start,
  599. X *    od = length of Differing end on screen,
  600. X *    nd = length of Differing end in data to be put.
  601. X */
  602. XHidden int
  603. Xput_line(y, xskip, data, len)
  604. Xint y, xskip;
  605. Xstring data;
  606. Xint len;
  607. X{
  608. X    register char *op, *oq, *np, *nq;
  609. X    int m1, od, nd, delta;
  610. X
  611. X    /* calculate the magic parameters */
  612. X    op = &line[y][xskip];
  613. X    oq = &line[y][lenline[y]-1];
  614. X    np = data;
  615. X    nq = data + len - 1;
  616. X    m1 = 0;
  617. X    while ((*op&SOCHAR) == (*np&SOCHAR) && op <= oq && np <= nq)
  618. X        op++, np++, m1++;
  619. X    od = oq - op + 1;
  620. X    nd = nq - np + 1;
  621. X    /* now we have the picture above */
  622. X
  623. X    if (od==0 && nd==0)
  624. X        return;
  625. X
  626. X    delta = nd - od;
  627. X    move(y, xskip + m1);
  628. X    if (nd > 0) {
  629. X        put_str(np, nd);
  630. X    }
  631. X    if (delta < 0) {
  632. X        clr_to_eol();
  633. X        return;
  634. X    }
  635. X    lenline[y] = xskip + len;
  636. X    if (cur_x == cols) {
  637. X        cur_y++;
  638. X        cur_x = 0;
  639. X    }
  640. X}
  641. X
  642. X/*
  643. X * Scrolling (part of) the screen up (or down, dy<0).
  644. X */
  645. X
  646. XVisible Procedure
  647. Xtrmscrollup(yfirst, ylast, by)
  648. Xregister int yfirst;
  649. Xregister int ylast;
  650. Xregister int by;
  651. X{
  652. X#ifdef TRACE
  653. Xfprintf(stderr, "\ttrmscrollup(%d, %d, %d);\n", yfirst, ylast, by);
  654. X#endif
  655. X    check_started(MESS(7906, "trmscrollup called outside trmstart/trmend"));
  656. X
  657. X    if (by == 0)
  658. X        return;
  659. X
  660. X    if (yfirst < 0)
  661. X        yfirst = 0;
  662. X    if (ylast >= lines)
  663. X        ylast = lines-1;
  664. X
  665. X    if (yfirst > ylast)
  666. X        return;
  667. X
  668. X    if (so_mode != Off)
  669. X        standend();
  670. X
  671. X    if (by > 0 && yfirst + by > ylast
  672. X        ||
  673. X        by < 0 && yfirst - by > ylast)
  674. X    {
  675. X        clear_lines(yfirst, ylast);
  676. X        return;
  677. X    }
  678. X
  679. X    switch (scr_mode) {
  680. X    case BIOS:
  681. X        biosscrollup(yfirst, ylast, by);
  682. X        break;
  683. X    case ANSI:
  684. X        if (by > 0 && yfirst == 0) {
  685. X            lf_scroll(ylast, by);
  686. X        }
  687. X        else if (by > 0) {
  688. X            move_lines(yfirst+by, yfirst, ylast-yfirst+1-by, 1);
  689. X            clear_lines(ylast-by+1, ylast);
  690. X        }
  691. X        else {
  692. X            move_lines(ylast+by, ylast, ylast-yfirst+1+by, -1);
  693. X            clear_lines(yfirst, yfirst-by-1);
  694. X        }
  695. X        break;
  696. X    }
  697. X}
  698. X
  699. X/*
  700. X * Synchronization, move cursor to given position (or previous if < 0).
  701. X */
  702. X
  703. XVisible Procedure
  704. Xtrmsync(y, x)
  705. X    int y;
  706. X    int x;
  707. X{
  708. X#ifdef TRACE
  709. Xfprintf(stderr, "\ttrmsync(%d, %d);\n", y, x);
  710. X#endif
  711. X    check_started(MESS(7907, "trmsync called outside trmstart/trmend"));
  712. X
  713. X    if (0 <= y && y < lines && 0 <= x && x < cols) {
  714. X        move(y, x);
  715. X    }
  716. X    VOID fflush(stdout);
  717. X}
  718. X
  719. X/*
  720. X * Send a bell, visible if possible.
  721. X */
  722. X
  723. XVisible Procedure
  724. Xtrmbell()
  725. X{
  726. X#ifdef TRACE
  727. Xfprintf(stderr, "\ttrmbell();\n");
  728. X#endif
  729. X    check_started(MESS(7908, "trmbell called outside trmstart/trmend"));
  730. X    ring_bell();
  731. X}
  732. X
  733. X/*
  734. X * Now for the real work: here are all low level routines that really
  735. X * differ for BIOS or ANSI mode.
  736. X */
  737. X
  738. X/*
  739. X * BIOS video io is called by generating an 8086 software interrupt,
  740. X * using lattice's int86() function.
  741. X * To ease coding, all routines fill in the apropriate parameters in regs,
  742. X * and than call bios10(code), where code is to be placed in ah.
  743. X */
  744. X
  745. XHidden union REGS regs, outregs;
  746. X
  747. X/* A macro for speed  */
  748. X#define bios10(code) (regs.h.ah = (code), int86(0x10, ®s, ®s))
  749. X#define nbios10(code) (regs.h.ah = (code), int86(0x10, ®s, &outregs))
  750. X
  751. X/* Video attributes: (see the BASIC manual) (used for standout mode) */
  752. X
  753. XHidden int video_attr;
  754. X#ifndef GFX
  755. X#define V_NORMAL 7
  756. X#else
  757. X#define V_NORMAL (gfx_mode == TEXT_MODE ? 7 : 0)
  758. X#endif
  759. X#define V_STANDOUT (7<<4)
  760. X
  761. X/* Some BIOS only routines */
  762. X
  763. XHidden get_cols()
  764. X{
  765. X    bios10(15);
  766. X    return regs.h.ah;
  767. X}
  768. X
  769. X/*
  770. X * ANSI escape sequences
  771. X */
  772. X#define A_CUP    "\033[%d;%dH"   /* cursor position */
  773. X#define A_SGR0    "\033[0m"       /* set graphics rendition to normal */
  774. X#define A_SGR7    "\033[7m"       /* set graphics rendition to standout */
  775. X#define A_ED    "\033[2J"       /* erase display (and cursor home) */
  776. X#define A_EL    "\033[K"        /* erase (to end of) line */
  777. X
  778. X/*
  779. X * The following routine is the time bottleneck, I believe!
  780. X */
  781. X
  782. XHidden Procedure
  783. Xput_str(data, n)
  784. Xchar *data;
  785. Xint n;
  786. X{
  787. X    register char c, so;
  788. X
  789. X    so = so_mode;
  790. X    if (scr_mode == BIOS) {
  791. X        regs.x.cx = 1;    /* repition count */
  792. X        regs.h.bh = 0;    /* page number */
  793. X        regs.h.bl = video_attr;
  794. X        while (--n >= 0) {
  795. X            c = (*data++)&SOCHAR;
  796. X            if ((c&SOBIT) != so) {
  797. X                so = c&SOBIT;
  798. X                so ? standout() : standend();
  799. X                regs.h.bl = video_attr;
  800. X            }
  801. X            regs.h.al = c&CHAR;
  802. X            nbios10(9);
  803. X            if (cur_x >= cols-1) {
  804. X                line[cur_y][cols-1] = c;
  805. X                continue;
  806. X            }
  807. X            regs.h.dh = cur_y;
  808. X            regs.h.dl = cur_x + 1;
  809. X            nbios10(2);
  810. X            line[cur_y][cur_x] = c;
  811. X            cur_x++;
  812. X        }
  813. X    }
  814. X    else {
  815. X        while (--n >= 0) {
  816. X            c = (*data++)&SOCHAR;
  817. X            if ((c&SOBIT) != so) {
  818. X                so = c&SOBIT;
  819. X                so ? standout() : standend();
  820. X            }
  821. X            putch(c&CHAR);
  822. X            line[cur_y][cur_x] = c;
  823. X            cur_x++;
  824. X        }
  825. X    }
  826. X}
  827. X
  828. X/*
  829. X * Move to position y,x on the screen
  830. X */
  831. X
  832. XHidden Procedure
  833. Xmove(y, x)
  834. Xint y, x;
  835. X{
  836. X    if (scr_mode != BIOS && cur_y == y && cur_x == x)
  837. X        return;
  838. X    switch (scr_mode) {
  839. X    case BIOS:
  840. X        regs.h.dh = y;
  841. X        regs.h.dl = x;
  842. X        regs.h.bh = 0; /* Page; must be 0 for graphics */
  843. X        bios10(2);
  844. X        break;
  845. X    case ANSI:
  846. X        cprintf(A_CUP, y+1, x+1);
  847. X        break;
  848. X    }
  849. X    cur_y = y;
  850. X    cur_x = x;
  851. X}
  852. X
  853. XHidden Procedure
  854. Xstandout()
  855. X{
  856. X    so_mode = On;
  857. X    switch (scr_mode) {
  858. X    case BIOS:
  859. X        video_attr = V_STANDOUT;
  860. X        break;
  861. X    case ANSI:
  862. X        cputs(A_SGR7);
  863. X        break;
  864. X    }
  865. X}
  866. X
  867. XHidden Procedure
  868. Xstandend()
  869. X{
  870. X    so_mode = Off;
  871. X    switch (scr_mode) {
  872. X    case BIOS:
  873. X        video_attr = V_NORMAL;
  874. X        break;
  875. X    case ANSI:
  876. X        cputs(A_SGR0);
  877. X        break;
  878. X    }
  879. X}
  880. X
  881. X#ifdef UNUSED
  882. XHidden Procedure
  883. Xput_c(c)
  884. Xint c;
  885. X{
  886. X    int ch;
  887. X
  888. X    ch = c&CHAR;
  889. X#ifndef NDEBUG
  890. X    if (!isprint(ch)) {
  891. X        ch = '?';
  892. X        c = (c&SOBIT)|'?';
  893. X    }
  894. X#endif
  895. X    switch (scr_mode) {
  896. X    case BIOS:
  897. X        regs.h.al = ch;
  898. X        regs.h.bl = video_attr;
  899. X        regs.x.cx = 1;    /* repition count */
  900. X        regs.h.bh = 0;    /* page number */
  901. X        bios10(9);
  902. X        if (cur_x >= cols-1) {
  903. X            line[cur_y][cols-1] = c;
  904. X            return;
  905. X        }
  906. X        regs.h.dh = cur_y;
  907. X        regs.h.dl = cur_x + 1;
  908. X        bios10(2);
  909. X        break;
  910. X    case ANSI:
  911. X        putch(ch);
  912. X        break;
  913. X    }
  914. X    line[cur_y][cur_x] = c;
  915. X    cur_x++;
  916. X}
  917. X#endif UNUSED
  918. X
  919. XHidden Procedure
  920. Xclear_lines(yfirst, ylast)
  921. Xint yfirst, ylast ;
  922. X{
  923. X    register int y;
  924. X
  925. X    if (scr_mode == BIOS) {
  926. X        regs.h.al = 0;    /* scroll with al = 0 means blank window */
  927. X        regs.h.ch = yfirst;
  928. X        regs.h.cl = 0;
  929. X        regs.h.dh = ylast;
  930. X        regs.h.dl = cols-1;
  931. X        regs.h.bh = V_NORMAL;
  932. X        bios10(6);
  933. X        for (y = yfirst; y <= ylast; y++)
  934. X            lenline[y] = 0;
  935. X        return;
  936. X    }
  937. X    /* scr_mode == ANSI */
  938. X    if (yfirst == 0 && ylast == lines-1) {
  939. X        if (so_mode == On)
  940. X            standend();
  941. X        move(0, 0);        /* since some ANSI'd don't move */
  942. X        cputs(A_ED);
  943. X        cur_y = cur_x = 0;
  944. X        for (y = yfirst; y < ylast; y++)
  945. X            lenline[y] = 0;
  946. X        return;
  947. X    }
  948. X    for (y = yfirst; y <= ylast; y++) {
  949. X        if (lenline[y] > 0) {
  950. X            move(y, 0);
  951. X            clr_to_eol();
  952. X        }
  953. X    }
  954. X}
  955. X
  956. XHidden Procedure
  957. Xclr_to_eol()
  958. X{
  959. X    if (so_mode == On)
  960. X        standend();
  961. X    switch (scr_mode) {
  962. X    case BIOS:
  963. X        regs.h.bh = 0;    /* page */
  964. X        regs.x.cx = lenline[cur_y] - cur_x;
  965. X        regs.h.al = ' ';
  966. X        regs.h.bl = V_NORMAL;
  967. X        bios10(9);
  968. X        break;
  969. X    case ANSI:
  970. X        cputs(A_EL);
  971. X        break;
  972. X    }
  973. X    lenline[cur_y] = cur_x;
  974. X}
  975. X
  976. XHidden Procedure        /* scrolling for BIOS */
  977. Xbiosscrollup(yfirst, ylast, by)
  978. Xint yfirst;
  979. Xint ylast;
  980. Xint by;
  981. X{
  982. X    regs.h.al = (by < 0 ? -by : by);
  983. X    regs.h.ch = yfirst;
  984. X    regs.h.cl = 0;
  985. X    regs.h.dh = ylast;
  986. X    regs.h.dl = cols-1;
  987. X    regs.h.bh= V_NORMAL;
  988. X    bios10(by < 0 ? 7 : 6);
  989. X    cur_y = cur_x = Undefined;
  990. X    if (by > 0)
  991. X        scr_lines(yfirst, ylast, by, 1);
  992. X    else
  993. X        scr_lines(ylast, yfirst, -by, -1);
  994. X}
  995. X
  996. XHidden Procedure        /* Reset internal administration accordingly */
  997. Xscr_lines(yfrom, yto, n, dy)
  998. Xint yfrom, yto, n, dy;
  999. X{
  1000. X    register int y, x;
  1001. X    char *saveln;
  1002. X
  1003. X    while (n-- > 0) {
  1004. X        saveln = line[yfrom];
  1005. X        for (y = yfrom; y != yto; y += dy) {
  1006. X            line[y] = line[y+dy];
  1007. X            lenline[y] = lenline[y+dy];
  1008. X        }
  1009. X        line[yto] = saveln;
  1010. X        for (x = 0; x < cols; x++ )
  1011. X            line[yto][x] = ' ';
  1012. X        lenline[yto] = 0;
  1013. X    }
  1014. X}
  1015. X
  1016. XHidden Procedure
  1017. Xlf_scroll(yto, by)
  1018. Xint yto;
  1019. Xint by;
  1020. X{
  1021. X    register int n = by;
  1022. X
  1023. X    move(lines-1, 0);
  1024. X    while (n-- > 0) {
  1025. X        putch('\n');
  1026. X    }
  1027. X    scr_lines(0, lines-1, by, 1);
  1028. X    move_lines(lines-1-by, lines-1, lines-1-yto, -1);
  1029. X    clear_lines(yto-by+1, yto);
  1030. X}
  1031. X
  1032. XHidden Procedure        /* for dumb scrolling, uses and updates */
  1033. Xmove_lines(yfrom, yto, n, dy)    /* internal administration */
  1034. Xint yfrom;
  1035. Xint yto;
  1036. Xint n;
  1037. Xint dy;
  1038. X{
  1039. X    while (n-- > 0) {
  1040. X        put_line(yto, 0, line[yfrom], lenline[yfrom]);
  1041. X        yfrom += dy;
  1042. X        yto += dy;
  1043. X    }
  1044. X}
  1045. X
  1046. XHidden Procedure ring_bell()
  1047. X{
  1048. X    switch (scr_mode) {
  1049. X    case BIOS:
  1050. X        regs.h.al = '\007';
  1051. X        regs.h.bl = V_NORMAL;
  1052. X        bios10(14);
  1053. X        break;
  1054. X    case ANSI:
  1055. X        putch('\007');
  1056. X        break;
  1057. X    }
  1058. X}
  1059. X
  1060. X/*
  1061. X * Show the current internal statuses of the screen on stderr.
  1062. X * For debugging only.
  1063. X */
  1064. X
  1065. X#ifdef SHOW
  1066. XVisible Procedure
  1067. Xtrmshow(s)
  1068. Xchar *s;
  1069. X{
  1070. X    int y, x;
  1071. X
  1072. X    fprintf(stderr, "<<< %s >>>\n", s);
  1073. X    for (y = 0; y < lines; y++) {
  1074. X        for (x = 0; x <= lenline[y] /*** && x < cols ***/ ; x++) {
  1075. X            fputc(line[y][x]&CHAR, stderr);
  1076. X        }
  1077. X        fputc('\n', stderr);
  1078. X        for (x = 0; x <= lenline[y] && x < cols-1; x++) {
  1079. X            if (line[y][x]&SOBIT)
  1080. X                fputc('-', stderr);
  1081. X            else
  1082. X                fputc(' ', stderr);
  1083. X        }
  1084. X        fputc('\n', stderr);
  1085. X    }
  1086. X    fprintf(stderr, "CUR_Y = %d, CUR_X = %d.\n", cur_y, cur_x);
  1087. X    VOID fflush(stderr);
  1088. X}
  1089. X#endif
  1090. X
  1091. X/*
  1092. X * Interrupt handling.
  1093. X *
  1094. X * (This has not properly been tested, nor is it clear that
  1095. X * this interface is what we want.  Anyway, it's here for you
  1096. X * to experiment with.  What does it do, you may ask?
  1097. X * Assume an interactive program which reads its characters
  1098. X * through trminput.  Assume ^C is the interrupt character.
  1099. X * Normally, ^C is treated just like any other character: when
  1100. X * typed, it turns up in the input.  The program may understand
  1101. X * input ^C as "quit from the current mode".
  1102. X * Occasionally, the program goes into a long period of computation.
  1103. X * Now it would be uninterruptible, except if it calls trminterrupt
  1104. X * at times in its computational loop.  Trminterrupt magically looks
  1105. X * ahead in the input queue, and if it sees a ^C, discards all input
  1106. X * before that point and returns Yes.  It also sets a flag, so that
  1107. X * the interupt "sticks around" until either trminput or trmavail
  1108. X * is called.  It is undefined whether typing ^C several times in
  1109. X * a row is seen as one interrupt, or an interrupt followed by input
  1110. X * of ^C's.  A program should be prepared for either.)
  1111. X */
  1112. X
  1113. Xstatic bool intrflag= No;
  1114. X
  1115. Xstatic
  1116. Xhandler(sig)
  1117. X    int sig;
  1118. X{
  1119. X    signal(sig, handler);
  1120. X    intrflag= Yes;
  1121. X}
  1122. X
  1123. Xstatic
  1124. Xset_handler()
  1125. X{
  1126. X    signal(SIGINT, handler);
  1127. X}
  1128. X
  1129. Xbool
  1130. Xtrminterrupt()
  1131. X{
  1132. X    /* Force a check for Control-break which will call handler. */
  1133. X    kbhit();
  1134. X    return intrflag;
  1135. X}
  1136. X
  1137. X/*
  1138. X * Terminal input without echo.
  1139. X * (This is a recent addition to this module, but will soon be standard).
  1140. X */
  1141. X
  1142. Xtrminput()
  1143. X{
  1144. X    intrflag= No;
  1145. X    return bdos(0x7, 0, 0) & 0377; /* Input, no echo, no ^C checks */
  1146. X}
  1147. X
  1148. X/*
  1149. X * Check for character available.
  1150. X *
  1151. X * To do this properly, should call DOS function 6,
  1152. X * but the relevant bit (the Z flag) can't be checked from C.
  1153. X * For now, say we don't know.
  1154. X */
  1155. X
  1156. Xtrmavail()
  1157. X{
  1158. X    intrflag= No;
  1159. X    return -1;
  1160. X}
  1161. X
  1162. Xtrmsuspend()
  1163. X{
  1164. X    /* Not implementable on MS-DOS */
  1165. X}
  1166. @//E*O*F p1trm.c//
  1167. if test 21268 -ne "`wc -c <'p1trm.c'`"; then
  1168.     echo shar: error transmitting "'p1trm.c'" '(should have been 21268 characters)'
  1169. fi
  1170. fi # end of overwriting check
  1171. echo shar: extracting "'trm.h'" '(879 characters)'
  1172. if test -f 'trm.h' ; then 
  1173.   echo shar: will not over-write existing file "'trm.h'"
  1174. else
  1175. sed 's/^X//' >trm.h <<'@//E*O*F trm.h//'
  1176. X/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1986. */
  1177. X
  1178. X/*
  1179. X * Terminal capabilities.  These correspond to bits set by trmstart in its
  1180. X * parameter flags parameter.
  1181. X */
  1182. X
  1183. X#define HAS_STANDOUT    1    /* Terminal has inverse video or underline */
  1184. X#define CAN_SCROLL    2    /* Terminal can insert/delete lines */
  1185. X#define CAN_OPTIMISE    4    /* Terminal can insert/delete characters */
  1186. X#define CAN_SENSE    8    /* Terminal can send cursor position */
  1187. X
  1188. X/*
  1189. X * Error codes returned by trmstart.
  1190. X */
  1191. X
  1192. X#define TE_OK        0    /* No errors */
  1193. X#define TE_TWICE    1    /* Trmstart called again */
  1194. X#define TE_NOTERM    2    /* $TERM not set or empty */
  1195. X#define TE_BADTERM    3    /* $TERM not found in termcap database */
  1196. X#define TE_DUMB        4    /* Terminal too dumb */
  1197. X#define TE_NOTTY    5    /* Stdout not a tty device */
  1198. X#define TE_NOMEM    6    /* Can't get enough memory */
  1199. X#define TE_OTHER    7    /* This and higher are reserved errors */
  1200. @//E*O*F trm.h//
  1201. if test 879 -ne "`wc -c <'trm.h'`"; then
  1202.     echo shar: error transmitting "'trm.h'" '(should have been 879 characters)'
  1203. fi
  1204. fi # end of overwriting check
  1205. echo shar: extracting "'MANIFEST'" '(270 characters)'
  1206. if test -f 'MANIFEST' ; then 
  1207.   echo shar: will not over-write existing file "'MANIFEST'"
  1208. else
  1209. sed 's/^X//' >MANIFEST <<'@//E*O*F MANIFEST//'
  1210. X  File Name             Kit #   Description
  1211. X-----------------------------------------------------------
  1212. X MANIFEST                  1   This shipping list
  1213. X README                    1
  1214. X p1trm.c                   1
  1215. X trm.h                     1
  1216. X vtrm.c                    2
  1217. @//E*O*F MANIFEST//
  1218. if test 270 -ne "`wc -c <'MANIFEST'`"; then
  1219.     echo shar: error transmitting "'MANIFEST'" '(should have been 270 characters)'
  1220. fi
  1221. fi # end of overwriting check
  1222. echo shar: "End of archive 1 (of 2)."
  1223. cp /dev/null ark1isdone
  1224. DONE=true
  1225. for I in 1 2; do
  1226.     if test -! f ark${I}isdone; then
  1227.         echo "You still need to run archive ${I}."
  1228.         DONE=false
  1229.     fi
  1230. done
  1231. case $DONE in
  1232.     true)
  1233.         echo "You have run all 2 archives."
  1234.         echo 'Now see the README'
  1235.         ;;
  1236. esac
  1237. ##  End of shell archive.
  1238. exit 0
  1239.